有些概念但細節不明確,我們不希望也不能直接實作出來,那我們就可以依此抽象概念先使用抽象類別列出抽象屬性及抽象函數,讓繼承他的子類別去實作出來。
依照之前提過類別像藍圖的概念來說,那抽象類別就像草圖,繼承抽象類別的子類別像藍圖,最後依藍圖實例化出實例。
abstract class SomeClass() {
abstract val foo: String
abstract fun bar(): String
}
//抽象父類別
abstract class House(val id: String, val room: Int, var price: Int) {
//一個抽象屬性
abstract val type: String
//兩個抽象函數:沒有函數本體
abstract fun getBasicInfo(): String
abstract fun getExtraInfo(): String
//一般函數:印出所有訊息
fun getAllInfo() {
println(getBasicInfo() + "\n" + getExtraInfo())
}
}
//子類別
class Apartment(id: String, room: Int, price: Int, private val floor: Int, private var houseAge: Int) :
House(id, room, price) {
//實作抽象屬性
override val type: String = "Apartment"
//實作兩個抽象類別
override fun getBasicInfo(): String {
return "id: $id , type: $type , room: $room ,price: $price"
}
override fun getExtraInfo(): String {
return " floor: $floor , houseAge: $houseAge "
}
}
fun main() {
//實作Apartment
val apartment = Apartment("ap0001", 4, 500, 5, 22)
//直接呼叫非抽象的函數
apartment.getAllInfo()
//結果:
// id: ap0001 , type: Apartment , room: 4 ,price: 500
// floor: 5 , houseAge: 22
}
介面的用途就是先約定一些屬性和行為在類別之間共用,而共用就是介面的目的。
介面只是定義用途,不管怎麼實作。所以它沒有建構函數這個初始化工具,裡面的定義的函數也沒有函數本體。
直接看例子:
interface Usb {
fun enable() //抽象函數,前面省略了public abstract
fun close()
val deriveName: String //一般的屬性,介面中宣告屬性只能透過getter
get() = "USB"
fun printDeriveName(){ //一般函數
println(deriveName)
}
}
:
,如果還有父類別的話以逗號隔開class Mouse : Usb {
override val deriveName: String //可選要不要覆寫
get() = "mouse"
//兩個抽象函數必須實作
override fun enable() {
println("Mouse inserted")
}
override fun close() {
println("Unplugged the Mouse")
}
}
class Keyboard : Usb {
//兩個抽象函數必須實作
override fun enable() {
println("Keyboard inserted")
}
override fun close() {
println("Unplugged the Keyboard")
}
override val deriveName: String //可選要不要覆寫
get() = "Keyboard"
}
class Computer {
fun bootUp() {
println("Computer boot up")
}
fun shutDown() {
println("Computer shut down")
}
//使用Usb連結Mouse、Keyboard等設備
fun useEquipment(usb: Usb) {
usb.printDeriveName()
usb.enable()
usb.close()
}
}
fun main() {
val computer = Computer()
val mouse = Mouse()
val keyboard = Keyboard()
computer.apply {
bootUp()
useEquipment(mouse)
useEquipment(keyboard)
shutDown()
}
/* 結果 :
Computer boot up
deriveName : mouse
Mouse inserted
Unplugged the Mouse
deriveName : Keyboard
Keyboard inserted
Unplugged the Keyboard
Computer shut down */
}
interface Name {
val name: String
}
//Person介面繼承Name介面,並實作抽象屬性name
interface Person : Name {
val firstname: String
val lastname: String
override val name: String
get() = "$firstname $lastname"
}
//實作Person介面,實作抽象屬性成為主建構函數的參數。
//因為name已被Person實作過,所以不一定要覆寫它
class Student(
override val firstname: String,
override val lastname: String,
private val studentId: Int
) : Person
interface A {
fun foo(){
print("A")
}
fun bar() //抽象函數
}
interface B{
fun foo(){
print("B")
}
fun bar(){
println("bar")
}
}
super<A>.foo()
這種語法在尖括號中指定介面。(發生衝突的函數必須是已完成的函數,這樣主程式才知道怎麼執行)class C:A{
override fun bar() {
println("A bar")
}
}
class D :A,B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
兩者該如何選擇使用呢? 好像不能因為是大人所以同時全都要
針對如何使用,有個不錯的經驗法則:
在需要一組公共物件行為或屬性時,如果繼承行不通就改用介面。
另一方面,如果繼承可行,但又不太需要太具體的父類別時,便採用抽象類別
(如果還想產生父類別的實例就只能使用一般類別)
節錄自 Kotlin權威2.0
明天見